package com.ruoyi.wvp.service.impl;

import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.wvp.domain.Surveillance;
import com.ruoyi.wvp.entity.AddressUnitList;
import com.ruoyi.wvp.utils.PermissionUtil;
import jakarta.transaction.Transactional;
import jakarta.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.wvp.mapper.AddressUnitMapper;
import com.ruoyi.wvp.domain.AddressUnit;
import com.ruoyi.wvp.service.IAddressUnitService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.enums.DeletedEnum;
import com.ruoyi.common.utils.StringUtils;

import java.util.stream.Collectors;

/**
 * 行政单位Service业务层处理
 *
 * @author ruoyi
 * @date 2024-07-22
 */
@Service
@Slf4j
public class AddressUnitServiceImpl extends ServiceImpl<AddressUnitMapper, AddressUnit> implements IAddressUnitService {
    @Autowired
    private AddressUnitMapper addressUnitMapper;


    @Autowired
    protected Validator validator;

    /**
     * 查询行政单位
     *
     * @param id 行政单位主键
     * @return 行政单位
     */
    @Override
    public AddressUnit selectAddressUnitById(Long id) {
        return addressUnitMapper.selectAddressUnitById(id);
    }

    /**
     * 查询行政单位列表
     *
     * @param addressUnit 行政单位
     * @return 行政单位
     */
    @Override
    public List<AddressUnit> selectAddressUnitList(AddressUnit addressUnit) {
        return addressUnitMapper.selectAddressUnitList(addressUnit);
    }

    /**
     * 新增行政单位
     *
     * @param addressUnit 行政单位
     * @return 结果
     */
    @Override
    public int insertAddressUnit(AddressUnit addressUnit) {
        addressUnit.setCreateTime(DateUtils.getNowDate());
        return addressUnitMapper.insertAddressUnit(addressUnit);
    }

    /**
     * 修改行政单位
     *
     * @param addressUnit 行政单位
     * @return 结果
     */
    @Override
    public int updateAddressUnit(AddressUnit addressUnit) {
        addressUnit.setUpdateTime(DateUtils.getNowDate());
        return addressUnitMapper.updateAddressUnit(addressUnit);
    }

    /**
     * 批量删除行政单位
     *
     * @param ids 需要删除的行政单位主键
     * @return 结果
     */
    @Override
    public int deleteAddressUnitByIds(Long[] ids) {
        return addressUnitMapper.deleteAddressUnitByIds(ids);
    }

    /**
     * 删除行政单位信息
     *
     * @param id 行政单位主键
     * @return 结果
     */
    @Override
    public int deleteAddressUnitById(Long id) {
        return addressUnitMapper.deleteAddressUnitById(id);
    }


    @Override
    public Page<AddressUnit> pageList(Page<AddressUnit> page, AddressUnit addressUnit) {
        LambdaQueryWrapper<AddressUnit> queryWrapper = getQueryWrapper(addressUnit);
        return page(page, queryWrapper);
    }

    @Override
    public List<AddressUnit> listAll(AddressUnit addressUnit) {
        return list(getQueryWrapper(addressUnit));
    }

    private LambdaQueryWrapper<AddressUnit> getQueryWrapper(AddressUnit addressUnit) {
        LambdaQueryWrapper<AddressUnit> queryWrapper = Wrappers.lambdaQuery(AddressUnit.class);
        queryWrapper.eq(AddressUnit::getDeleted, DeletedEnum.NOMAL.getValue());

//        父部门id
        if (Objects.nonNull(addressUnit.getParentId())) {
            queryWrapper.eq(AddressUnit::getParentId, addressUnit.getParentId());
        }


//        祖级列表
        if (StringUtils.isNotEmpty(addressUnit.getAncestors())) {
            queryWrapper.likeLeft(AddressUnit::getAncestors, addressUnit.getAncestors());
        }


//        名称
        if (StringUtils.isNotEmpty(addressUnit.getName())) {
            queryWrapper.like(AddressUnit::getName, addressUnit.getName());
        }


//        状态（0正常 1停用）
        if (StringUtils.isNotEmpty(addressUnit.getStatus())) {
            queryWrapper.eq(AddressUnit::getStatus, addressUnit.getStatus());
        }
        if (Objects.nonNull(addressUnit.getLevel())) {
            queryWrapper.le(AddressUnit::getLevel, addressUnit.getLevel());
        }


        return queryWrapper;
    }

    @Override
    @Transactional
    public int edit(AddressUnit addressUnit) {
        addressUnit.setUpdateBy(SecurityUtils.getUsername());
        addressUnit.setUpdateTime(new Date());
        AddressUnit newParentAddressUnit = addressUnitMapper.selectById(addressUnit.getParentId());
        AddressUnit oldAddressUnit = addressUnitMapper.selectById(addressUnit.getId());
        if (StringUtils.isNotNull(newParentAddressUnit) && StringUtils.isNotNull(oldAddressUnit)) {
            String newAncestors = newParentAddressUnit.getAncestors() + "," + newParentAddressUnit.getId();
            String oldAncestors = oldAddressUnit.getAncestors();
            addressUnit.setAncestors(newAncestors);
            addressUnit.setLevel(getLevelByActors(newAncestors));
            updateDeptChildren(addressUnit.getId(), newAncestors, oldAncestors);
        }
        if (UserConstants.DEPT_NORMAL.equals(addressUnit.getStatus()) && StringUtils.isNotEmpty(addressUnit.getAncestors())
                && !StringUtils.equals("0", addressUnit.getAncestors())) {
            // 如果该部门是启用状态，则启用该部门的所有上级部门
            updateParentStatusNormal(addressUnit);
        }
        return addressUnitMapper.updateById(addressUnit);
    }

    private void updateParentStatusNormal(AddressUnit addressUnit) {
        String ancestors = addressUnit.getAncestors();
        Long[] ids = Convert.toLongArray(ancestors);
        AddressUnit updateData = new AddressUnit();
        updateData.setStatus("0");
        addressUnitMapper.update(updateData, Wrappers.<AddressUnit>lambdaUpdate().in(AddressUnit::getId, ids));
    }

    @Transactional
    public void updateDeptChildren(Long id, String newAncestors, String oldAncestors) {
        LambdaQueryWrapper<AddressUnit> queryWrapper = Wrappers.lambdaQuery(AddressUnit.class).eq(AddressUnit::getParentId, id);
        List<AddressUnit> children = addressUnitMapper.selectList(queryWrapper);
        for (AddressUnit child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
            child.setLevel(getLevelByActors(newAncestors+','+id));
            child.setUpdateBy(SecurityUtils.getUsername());
            child.setUpdateTime(new Date());
            updateDeptChildren(child.getId(), newAncestors+','+id,oldAncestors+','+id);
        }
        if (children.size() > 0) {
            addressUnitMapper.updateById(children);
        }
    }


    @Override
    public String importData(List<AddressUnit> list, boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(list) || list.size() == 0) {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();

        List<AddressUnit> addressUnits = listAll(new AddressUnit());
        Map<String, AddressUnit> addressUnitMap = addressUnits.stream().collect(Collectors.toMap(AddressUnit::getName, s -> s));
        for (AddressUnit item : list) {
            try {
                // 验证是否存在这个用户
                AddressUnit u = addressUnitMap.get(item.getName());
                if (StringUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, item);
                    addAddressUnitN(operName, item, addressUnitMap);

                    successNum++;
                    successMsg.append("<br/>" + successNum + "、名称 " + item.getName() + " 导入成功");
                } else if (isUpdateSupport) {
                    BeanValidators.validateWithException(validator, item);
                    item.setId(u.getId());
                    item.setUpdateBy(operName);
                    item.setUpdateTime(new Date());
                    AddressUnit parentUnit = addressUnitMap.get(item.getParentName());
                    if (Objects.nonNull(parentUnit)) {
                        item.setParentId(parentUnit.getId());
                        item.setAncestors(parentUnit.getAncestors() + "," + parentUnit.getId());
                        item.setLevel(getLevelByActors(item.getAncestors()));
                    }
                    updateById(item);
                    addressUnitMap.put(item.getName(), item);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、名称 " + item.getName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、名称 " + item.getName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、名称 " + item.getName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Transactional(value = Transactional.TxType.REQUIRES_NEW)
    public void addAddressUnitN(String operName, AddressUnit item, Map<String, AddressUnit> addressUnitMap) {
        AddressUnit parentUnit = addressUnitMap.get(item.getParentName());
        if (Objects.nonNull(parentUnit)) {
            item.setParentId(parentUnit.getId());
            item.setAncestors(parentUnit.getAncestors() + "," + parentUnit.getId());
            item.setLevel(getLevelByActors(item.getAncestors()));
        }
        item.setCreateBy(operName);
        item.setCreateTime(new Date());
        save(item);
        addressUnitMap.put(item.getName(), item);
    }


    public int getLevelByActors(String actors) {
        if (StringUtils.isBlank(actors)) {
            return 0;
        }
        return actors.split(",").length;
    }

    public void updateLevel() {
        List<AddressUnit> addressUnits = listAll(new AddressUnit());
        addressUnits.forEach(addressUnit -> {
            AddressUnit updateUnit = new AddressUnit();
            updateUnit.setId(addressUnit.getId());
            updateUnit.setLevel(getLevelByActors(addressUnit.getAncestors()));
            updateById(updateUnit);
        });
    }

    @Override
    public AddressUnitList streetList() {
        AddressUnitList addressUnitList = new AddressUnitList();
        List<AddressUnit> streeList = addressUnitMapper.getStreeList(SecurityUtils.getDeptId());
        if (CollectionUtils.isEmpty(streeList)) {
            return addressUnitList;
        }
        addressUnitList.setStreetList(streeList);
        List<Long> parentIds = streeList.stream().map(AddressUnit::getParentId).collect(Collectors.toList());
        LambdaQueryWrapper<AddressUnit> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AddressUnit::getLevel, 2)
                .eq(AddressUnit::getDeleted, DeletedEnum.NOMAL.getValue())
                .in(AddressUnit::getId, parentIds);
        List<AddressUnit> areaList = list(wrapper);
        if (CollectionUtils.isEmpty(areaList)) {
            return addressUnitList;
        }
        addressUnitList.setAreaList(areaList);

        List<Long> cityIds = areaList.stream().map(AddressUnit::getParentId).collect(Collectors.toList());
        wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AddressUnit::getLevel, 1)
                .eq(AddressUnit::getDeleted, DeletedEnum.NOMAL.getValue())
                .in(AddressUnit::getId, cityIds);
        List<AddressUnit> cityList = list(wrapper);
        if (CollectionUtils.isEmpty(cityList)) {
            return addressUnitList;
        }
        addressUnitList.setCityList(cityList);
        return addressUnitList;
    }


}
